

#include "gc_memory.h"

MCBPtr firstMCB=NULL;
char* memory = NULL;

void M_INIT(){
	memory=(char*)malloc(MEMSIZE*sizeof(char));
}


size_t memsize=MEMSIZE;



size_t common_size(size_t size)
{
	return size+sizeof(MCB);
}

size_t find_free_space_before_first_mcb()
{
	if (firstMCB == NULL)
	{
		return memsize;
	}

	return (size_t)firstMCB - (size_t)memory;
}

size_t calc_free_space_after(MCBPtr mcb)
{
	if (mcb->next == NULL)
	{
		return (size_t)memory + memsize - ((size_t)mcb + common_size(mcb->meta.size));
	}

	return ((size_t)mcb->next) - ((size_t)mcb + common_size(mcb->meta.size));
}

int check_mcb(MCBPtr mcb)
{
	MCBPtr curr = firstMCB;
	while(curr != NULL)
	{
		if (curr == mcb)
		{
			return 0;
		}
		curr = curr -> next;
	}
	return 1;
}


MCBPtr find_free_space(size_t size)
{
	if (firstMCB == NULL)
	{
		if (common_size(size) <= memsize)
		{
			firstMCB = (MCBPtr) memory;
			firstMCB->meta.size = size;
			firstMCB->next = NULL;

			//fill_map(firstMCB);
			return firstMCB;
		}
		else
		{
			return NULL;
		}
	}

	MCBPtr curr = firstMCB;

	if (find_free_space_before_first_mcb() >= common_size(size))
	{
		firstMCB = (MCBPtr) memory;
		firstMCB->meta.size = size;
		firstMCB->next = curr;

		//fill_map(firstMCB);
		return firstMCB;
	}

	while(curr != NULL)
	{
		if (calc_free_space_after(curr) >= size+sizeof(MCB))
		{
			MCBPtr allocated = (MCBPtr)((size_t)curr+common_size(curr->meta.size));
			allocated->meta.size = size;
			allocated->next = curr->next;
			curr->next = allocated;

		//	fill_map(allocated);
			return allocated;
		}
		curr = curr->next;
	}

	return NULL;
}

void* my_alloc(size_t size)
{
	MCBPtr ptr = find_free_space(size);

	if (ptr == NULL)
	{
		return NULL;
	}

	return (void *)((size_t)ptr + sizeof(MCB));
}

//char* allocate(size_t size)
//{
//	void* ptr = my_alloc(size);
//	char* response = (char*) calloc(21, sizeof(char));
//	if (ptr == NULL)
//	{
//		response[0] = '-';
//	}
//	else
//	{
//		snprintf(response, 20, "+ %u", (size_t)ptr - (size_t)memory);
//	}
//	return response;
//}

MCBPtr find_previous(MCBPtr mcb)
{
	MCBPtr curr = firstMCB;
	while(curr != NULL && curr->next != mcb)
	{
		curr = curr->next;
	}

	return curr;
}

int my_delete(void* ptr)
{
	if ((size_t) ptr < (size_t)memory+sizeof(MCB))
	{
		//fprintf(stderr, "%s\n", "Invalid pointer");
		return 1;
	}

	MCBPtr mcb = (MCBPtr)((size_t) ptr - sizeof(MCB));

	if (check_mcb(mcb) != 0)
	{
		//fprintf(stderr, "%s\n", "Invalid pointer");
		return 1;
	}

	if (mcb == firstMCB)
	{
		firstMCB = firstMCB->next;
	}
	else
	{
		MCBPtr prev = find_previous(mcb);
		if (prev == NULL)
		{
			return 1;
		}
		prev->next = mcb->next;
	}

	//clear_map(mcb);

	return 0;
}

//void get_meta (void * ptr, meta_s *meta){
//	MCBPtr mcb=(MCBPtr)((size_t)ptr-sizeof(MCB));
//	//printf("%i",(*mcb).meta.size);
//	meta=&(mcb->meta);
//}

meta_s* get_meta (void * ptr){
	return &(((MCBPtr)(ptr-sizeof(MCB)))->meta);
}

